package com.mjf.hash;

import java.util.Scanner;

/**
 * 哈希表
 * <p>
 * 可作为轻量级的缓存层，数据在内存中比持久化层（数据库）效率要高
 */
public class HashTabDemo {
    public static void main(String[] args) {

        // 创建哈希表
        HashTab hashTab = new HashTab(7);

        // 菜单
        String key = "";
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println();
            System.out.println("add:添加雇员");
            System.out.println("get:查找雇员");
            System.out.println("list:显示雇员");
            System.out.println("exit:退出系统");

            key = scanner.next();
            int id;
            String name;
            switch (key) {
                case "add":
                    System.out.println("请输入雇员ID：");
                    id = scanner.nextInt();
                    System.out.println("请输入雇员姓名：");
                    name = scanner.next();
                    hashTab.add(new Emp(id, name));
                    break;
                case "get":
                    System.out.println("请输入雇员ID：");
                    id = scanner.nextInt();
                    hashTab.get(id);
                    break;
                case "list":
                    hashTab.list();
                    break;
                case "exit":
                    scanner.close();
                    System.exit(0);
            }
        }

    }
}

/**
 * 哈希表，管理多条链表
 */
class HashTab {

    private final LinkedList[] linkedLists;
    private final int size;

    public HashTab(int size) {
        this.size = size;
        this.linkedLists = new LinkedList[size];

        for (int i = 0; i < size; i++) {
            this.linkedLists[i] = new LinkedList();
        }
    }

    /**
     * 添加元素
     */
    public void add(Emp emp) {
        int index = hash(emp.getId());
        this.linkedLists[index].add(emp);
    }

    /**
     * 查找元素
     */
    public void get(int id) {
        int index = hash(id);
        Emp res = this.linkedLists[index].get(id);
        if (res == null) {
            System.out.printf("ID %d 不存在\n", id);
        } else {
            System.out.printf("ID %d 信息为%s\n", id, res);
        }
    }

    /**
     * 遍历哈希表
     */
    public void list() {
        for (int i = 0; i < size; i++) {
            linkedLists[i].list(i + 1);
        }
    }

    /**
     * 散列函数
     */
    private int hash(int id) {
        return id % size;
    }
}

/**
 * 链表
 */
class LinkedList {

    // 链表头节点，默认为null
    private Emp head;

    /**
     * 添加元素到链表最后
     */
    public void add(Emp emp) {
        if (head == null) {
            head = emp;
            return;
        }
        Emp temp = head;
        while (temp.getNext() != null) {
            temp = temp.getNext();  // 节点后移
        }
        temp.setNext(emp);
    }

    /**
     * 根据ID查找
     */
    public Emp get(int id) {
        if (head == null) {
            return null;
        } else if (id == head.getId()) {
            return head;
        }
        Emp temp = head;
        while (temp.getNext() != null) {
            temp = temp.getNext();
            if (id == temp.getId()) {
                return temp;
            }
        }
        return null;
    }

    /**
     * 遍历链表
     */
    public void list(int index) {
        if (head == null) {
            System.out.printf("第%d链表为空~~~\n", index);
            return;
        }
        System.out.printf("第%d链表信息为：\n", index);
        Emp temp = head;
        while (true) {
            System.out.println(temp);
            if (temp.getNext() == null) {
                break;
            }
            temp = temp.getNext();  // 节点后移
        }
    }

}

/**
 * 雇员
 */
class Emp {
    private int id;
    private String name;
    private Emp next;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Emp getNext() {
        return next;
    }

    public void setNext(Emp next) {
        this.next = next;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Emp{");
        sb.append("id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }
}
